﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.Linq.Expressions;
using BF.Model;
using System.Data.Objects;
using BF.Infrastructure;


namespace BF.Infrastructure
{
    public abstract class DALBase<T, TT> : IRepository<T>
        where T : class
        where TT : ObjectContext
    {
        private TT dataContext;
        private readonly ObjectSet<T> dbset;
        protected DALBase(IDatabaseFactory<TT> databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.CreateObjectSet<T>();
        }

        protected IDatabaseFactory<TT> DatabaseFactory
        {
            get;
            private set;
        }

        protected TT DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }
        public virtual void Add(T entity)
        {
            dbset.AddObject(entity);
        }
        public virtual void Delete(T entity)
        {
            dbset.DeleteObject(entity);
        }

        public virtual T GetModelByCondition(Expression<Func<T, bool>> predicate)
        {
            return dbset.Where(predicate).FirstOrDefault<T>();
        }

        public virtual List<T> GetList(Expression<Func<T, bool>> where,
            Expression<Func<T, object>> orderBy, PageModel pageModel, bool asce)
        {
            if (asce)
            {
                return dbset.Where(where)
                    .OrderBy(orderBy)
                    .Skip(pageModel.StartRecord)
                    .Take(pageModel.PageSize)
                    .ToList();
            }
            else
            {
                return dbset.Where(where)
                    .OrderByDescending(orderBy)
                    .Skip(pageModel.StartRecord)
                    .Take(pageModel.PageSize)
                    .ToList();
            }
        }

        public virtual List<T> GetList(Expression<Func<T, bool>> where,
            List<OrderBys<T>> orderBys, PageModel pageModel)
        {
            var query = dbset.Where(where);
            pageModel.RecordCount = dbset.Where(where).Count();
            bool isFirst = true;
            foreach (var item in orderBys)
            {
                if (isFirst)
                    if (item.IsAsce)
                        query = query.OrderBy(item.Exp);
                    else
                        query = query.OrderByDescending(item.Exp);
                else
                    if (item.IsAsce)
                        query = ((IOrderedQueryable<T>)query).ThenBy(item.Exp);
                    else
                        query = ((IOrderedQueryable<T>)query).ThenByDescending(item.Exp);
                isFirst = false;
            }
            return query.Skip(pageModel.StartRecord)
                .Take(pageModel.PageSize)
                .ToList();
        }

        public virtual bool ExecuteProcedure(string sqlText, params object[] parameters)
        {
            int count = -1;
            count = dataContext
                .ExecuteStoreQuery<int>(sqlText, parameters)
                .FirstOrDefault();
            return count > 0;
        }

        public virtual List<T> GetList(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).ToList();
        }

        public void Delete(Expression<Func<T, bool>> predicate)
        {
            IEnumerable<T> objects = dbset.Where<T>(predicate).AsEnumerable();
            foreach (T obj in objects)
                dbset.DeleteObject(obj);
        }

        public int GetRowCount(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).Count();
        }
    }

    /// <summary>
    /// 复杂排序
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class OrderBys<T> where T : class
    {
        private Expression<Func<T, object>> _exp;
        private bool _isAsce;

        /// <summary>
        /// 排序表达式
        /// </summary>
        public Expression<Func<T, object>> Exp
        {
            get
            {
                return this._exp;
            }
            set
            {
                this._exp = value;
            }
        }
        /// <summary>
        /// 是否升序
        /// </summary>
        public bool IsAsce
        {
            get
            {
                return this._isAsce;
            }
            set
            {
                this._isAsce = value;
            }
        }
    }
}
